package com.ruoyi.TimedTask.service.impl;

import com.ruoyi.TimedTask.domain.TimedTask;
import com.ruoyi.TimedTask.mapper.TimedTaskMapper;
import com.ruoyi.TimedTask.service.TimedTaskService;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.core.text.Convert;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.ShiroUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.FileUtils;
import com.ruoyi.company.utils.Util;
import com.ruoyi.framework.config.properties.ExportDbProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.util.*;

/**
 * 定时任务Service业务层处理
 *
 * @author zjh
 * @date 2022-04-30
 */
@Service
public class TimedTaskServiceImpl implements TimedTaskService {

    @Autowired
    private TimedTaskMapper timedTaskMapper;

    @Autowired
    private ExportDbProperties exportDbProperties;

    /**
     * 查询定时任务
     *
     * @param taskId 定时任务ID
     * @return 定时任务
     */
    @Override
    public TimedTask selectTimedTaskById(Long taskId) {
        return timedTaskMapper.selectTimedTaskById(taskId);
    }

    /**
     * 查询定时任务列表
     *
     * @param timedTask 定时任务
     * @return 定时任务
     */
    @Override
    public List<TimedTask> selectTimedTaskList(TimedTask timedTask) {
        return timedTaskMapper.selectTimedTaskList(timedTask);
    }


    /**
     * 新增定时任务
     *
     * @return 结果
     */
    @Override
    public List<TimedTask> selectTimedTaskByAllId() {
        return timedTaskMapper.selectTimedTaskByAllId();
    }

    /**
     * 新增定时任务
     *
     * @param timedTask 定时任务
     * @return 结果
     */
    @Override
    public int insertTimedTask(TimedTask timedTask) {
        List<TimedTask> mytimeLiat = timedTaskMapper.selectTimedTaskByAllId();
        String mytasktime = "null";
        List<TimedTask> model = new ArrayList();
        GregorianCalendar calendar = new GregorianCalendar();
        int hour = calendar.get(Calendar.HOUR_OF_DAY);
        int minute = calendar.get(Calendar.MINUTE);
        int second = calendar.get(Calendar.SECOND);

        String hour_str = String.valueOf(hour);
        String minute_str = String.valueOf(minute);
        String second_str = String.valueOf(second);

        String nowTime = hour_str + ":" + minute_str + ":" + second_str;
        String importantTime = "10:30:00";
        boolean wieth = compTime(nowTime, importantTime);
        if (wieth) {
            mytasktime = "3pm";
        } else {
            mytasktime = "10am";
        }
        for (TimedTask newtime : mytimeLiat) {
            Random r = new Random();
            int minWd = 18;
            int maxWd = 28; //18-28
            // System.out.println();

            int minSd = 45;
            int maxSd = 65;

            int ceshi = r.nextInt(maxWd) % (maxWd - minWd + 1) + minWd;
            int ceshiSd = r.nextInt(maxSd) % (maxSd - minSd + 1) + minSd;
            newtime.setRecordBy(newtime.getCorporateRepresentative());
            newtime.setTaskDate(DateUtils.getNowDate());
            newtime.setNormalTemp(String.valueOf(ceshi));
            newtime.setNormalHum(String.valueOf(ceshiSd));
            newtime.setCreateTime(DateUtils.getNowDate());
            newtime.setTaskTime(mytasktime);
            model.add(newtime);
        }
//        timedTask.setCreateBy(ShiroUtils.getLoginName());
        return timedTaskMapper.insertTimedTasks(model);
    }


    /**
     * 比较两个时间 时分秒 大小
     *
     * @param s1
     * @param s2
     * @return
     */
    public static boolean compTime(String s1, String s2) {
        try {
            if (s1.indexOf(":") < 0 || s1.indexOf(":") < 0) {
                System.out.println("格式不正确");
            } else {
                String[] array1 = s1.split(":");
                int total1 = Integer.valueOf(array1[0]) * 3600 + Integer.valueOf(array1[1]) * 60 + Integer.valueOf(array1[2]);
                String[] array2 = s2.split(":");
                int total2 = Integer.valueOf(array2[0]) * 3600 + Integer.valueOf(array2[1]) * 60 + Integer.valueOf(array2[2]);
                return total1 - total2 > 0 ? true : false;
            }
        } catch (NumberFormatException e) {
            // TODO Auto-generated catch block
            return true;
        }
        return false;
    }

    /**
     * 修改定时任务
     *
     * @param timedTask 定时任务
     * @return 结果
     */
    @Override
    public int updateTimedTask(TimedTask timedTask) {
        timedTask.setUpdateTime(DateUtils.getNowDate());
        timedTask.setUpdateBy(SecurityUtils.getLoginUser().getNickName());
        return timedTaskMapper.updateTimedTask(timedTask);
    }


    /**
     * 删除定时任务信息
     *
     * @param taskId 定时任务ID
     * @return 结果
     */
    @Override
    public int deleteTimedTaskById(Long taskId) {
        return timedTaskMapper.deleteTimedTaskById(taskId);
    }


    /**
     * 删除定时任务对象
     *
     * @param ids 需要删除的数据ID
     * @return 结果
     */
    @Override
    public int deleteTimedTaskByIds(String ids) {
        return timedTaskMapper.deleteTimedTaskByIds(Convert.toStrArray(ids));
    }

    /**
     * 定时任务 备份数据库sql信息
     */
    @Override
    public void exportDb() {
        String user = exportDbProperties.getUser();
        String password = exportDbProperties.getPassword();
        String host = exportDbProperties.getHost();
        String exportDatabaseName = exportDbProperties.getExportDatabaseName();
        String exportPath = exportDbProperties.getExportPath();
        String mysqlPath = exportDbProperties.getMysqlPath();
        File exportFile = new File(exportPath);
        if (!exportFile.exists()) {
            exportFile.mkdir();
        }

        File[] files = exportFile.listFiles();

        //保存七天的 判断文件是否大于七个
        assert files != null;

        //7天前的Date
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DATE, -7);
        Date d = cal.getTime();
        if (files.length > 7) {
            try {
                for (int i = 0; i < files.length; i++) {
                    File file = files[i];
                    Path path = file.toPath();
                    BasicFileAttributes basicFileAttributes = Files.readAttributes(path, BasicFileAttributes.class);
                    //创建时间
                    Instant instant = basicFileAttributes.creationTime().toInstant();
                    Date from = Date.from(instant);
                    if (d.compareTo(from) > 0) {
                        file.delete();
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        //日期
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String dateNowStr = sdf.format(date);
        try {
            Runtime rt = Runtime.getRuntime();
            // 调用 调用mysql的安装目录的命令
            Process child = rt.exec(mysqlPath + "/mysqldump -u" + user + " -p" + password + " -h" + host + " " + exportDatabaseName);
            // 设置导出编码为utf-8。这里必须是utf-8
            // 把进程执行中的控制台输出信息写入.sql文件，即生成了备份文件。注：如果不对控制台信息进行读出，则会导致进程堵塞无法运行
            InputStream in = child.getInputStream();// 控制台的输出信息作为输入流
            InputStreamReader xx = new InputStreamReader(in, "utf-8");
            // 设置输出流编码为utf-8。这里必须是utf-8，否则从流中读入的是乱码
            String inStr;
            StringBuffer sb = new StringBuffer("");
            String outStr;
            // 组合控制台输出信息字符串
            BufferedReader br = new BufferedReader(xx);
            while ((inStr = br.readLine()) != null) {
                sb.append(inStr + "\r\n");
            }
            outStr = sb.toString();
            // 要用来做导入用的sql目标文件：
            FileOutputStream fout;
            String fileName = exportPath + "sql" + dateNowStr + ".sql";
            fout = new FileOutputStream(fileName);

            OutputStreamWriter writer = new OutputStreamWriter(fout, "utf-8");
            writer.write(outStr);
            writer.flush();
            in.close();
            xx.close();
            br.close();
            writer.close();
            fout.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 定时备份文件，每日执行一次：
     * - 备份当前 profile 文件夹到日期命名的新目录中
     * - 压缩新目录为 zip
     * - 删除原始文件夹
     * - 清理超过 7 天的备份
     * - 最多保留最近 3 个备份压缩文件
     */
    @Override
    public void exportProfile() {
        String exportPath = exportDbProperties.getExportProfilePath();
        createDirIfNotExists(exportPath);

        String today = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        File todayDir = new File(exportPath, today);
        createDirIfNotExists(todayDir.getAbsolutePath());

        cleanOldDirectories(exportPath, 7);
        performBackup(todayDir, exportPath, today);
        cleanExcessBackups(exportPath, 3);
    }

    /**
     * 创建目录（如果不存在）
     */
    private void createDirIfNotExists(String path) {
        File dir = new File(path);
        if (!dir.exists()) {
            dir.mkdirs();
        }
    }
    /**
     * 删除超过 N 天的文件夹
     */
    private void cleanOldDirectories(String basePath, int days) {
        File[] files = new File(basePath).listFiles(File::isDirectory);
        if (files == null || files.length <= days) return;

        Calendar threshold = Calendar.getInstance();
        threshold.add(Calendar.DATE, -days);
        Date cutoffDate = threshold.getTime();

        for (File file : files) {
            try {
                BasicFileAttributes attr = Files.readAttributes(file.toPath(), BasicFileAttributes.class);
                Date creationDate = Date.from(attr.creationTime().toInstant());
                if (creationDate.after(cutoffDate)) {
                    deleteFileNew(file.getAbsolutePath());
                    System.out.println("过期备份已删除：" + file.getName());
                }
            } catch (IOException e) {
                System.err.println("读取文件属性失败：" + file.getName());
                e.printStackTrace();
            }
        }
    }

    /**
     * 执行备份并压缩
     */
    private void performBackup(File backupDir, String basePath, String dateStr) {
        try {
            // 复制 profile 文件夹内容
            Util.copyFolder(RuoYiConfig.getProfile(), backupDir.getAbsolutePath());

            // 压缩目录
            boolean success = FileUtils.zip(backupDir.getAbsolutePath(), basePath + dateStr + ".zip");
            if (!success) {
                System.err.println("压缩失败：" + backupDir.getName());
                return;
            }

            // 删除原始备份文件夹
            deleteFileNew(backupDir.getAbsolutePath());
        } catch (Exception e) {
            System.err.println(StringUtils.format("备份失败:{}", e.getMessage()));
            e.printStackTrace();
        }
    }

    /**
     * 只保留最近 N 个 `.zip` 备份文件（假设文件名为 yyyy-MM-dd.zip）
     */
    private void cleanExcessBackups(String basePath, int maxRetain) {
        File baseDir = new File(basePath);
        if (!baseDir.exists() || !baseDir.isDirectory()) return;

        // 只获取以 `.zip` 结尾的文件
        File[] zipFiles = baseDir.listFiles(file -> file.isFile() && file.getName().endsWith(".zip"));
        if (zipFiles == null || zipFiles.length <= maxRetain) return;

        // 根据文件名倒序（从新到旧）排序
        Arrays.sort(zipFiles, Comparator.comparing(File::getName).reversed());

        // 删除超过 maxRetain 个数以外的旧文件
        for (int i = maxRetain; i < zipFiles.length; i++) {
            boolean deleted = zipFiles[i].delete();
            System.out.println((deleted ? "✅" : "❌") + " 删除旧备份：" + zipFiles[i].getName());
        }
    }

    /**
     * 删除文件或清空文件夹
     */
    public static void deleteFileNew(String path) {
        File file = new File(path);
        if (!file.exists()) return;

        if (file.isFile()) {
            file.delete();
        } else {
            File[] children = file.listFiles();
            if (children != null) {
                for (File child : children) {
                    deleteFileNew(child.getAbsolutePath());
                }
            }
            file.delete();
        }
    }
}